/**
 * @file bull_hal_sys_mutex.c
 * @brief 
 * @author yejing (yejh@gongniu.cn)
 * @version 1.0
 * @date 2024-05-08
 * 
 * Copyright 2021-2023 GongNiu Inc. All Rights Reserved.
 * 
 */

#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/semphr.h"


#include "bull_hal_sys_system.h"
#include "bull_hal_sys_memory.h"
#include "bull_hal_sys_mutex.h"


#define portYIELD_FROM_ISR_ex( xSwitchRequired ) if( xSwitchRequired != pdFALSE ) portYIELD()

/***********************************************************
*************************micro define***********************
***********************************************************/
typedef xSemaphoreHandle THRD_MUTEX;

typedef struct
{
    THRD_MUTEX mutex;
}MUTEX_MANAGE,*P_MUTEX_MANAGE;


/***********************************************************
*************************variable define********************
***********************************************************/

/***********************************************************
*************************function define********************
***********************************************************/


/**
 * @brief 用于创建并初始化 bull mutex
 * 
 * @param[out] pMutexHandle 返回mutex句柄
 * @return int 0=成功，非0=失败
 */
int bull_hal_sys_mutex_create(MUTEX_HANDLE *pMutexHandle)
{
    if(!pMutexHandle)
        return OPRT_OS_ADAPTER_INVALID_PARM;
    
    P_MUTEX_MANAGE pMutexManage;
    pMutexManage = (P_MUTEX_MANAGE)bull_hal_sys_memory_malloc(sizeof(MUTEX_MANAGE));
    if(!(pMutexManage))
        return OPRT_OS_ADAPTER_MALLOC_FAILED;
    
#if defined(CREATE_RECURSION_MUTEX)
    pMutexManage->mutex = xSemaphoreCreateRecursiveMutex();
#else
    pMutexManage->mutex = xSemaphoreCreateMutex();
#endif

    if(NULL == pMutexManage->mutex) {
        return OPRT_OS_ADAPTER_MUTEX_CREAT_FAILED;
    }

    *pMutexHandle = (MUTEX_HANDLE)pMutexManage;

    return OPRT_OS_ADAPTER_OK;
}

/**
 * @brief  用于lock tuya mutex
 * 
 * @param[in] mutexHandle tuya mutex句柄
 * @return int 0=成功，非0=失败
 */
int bull_hal_sys_mutex_lock(const MUTEX_HANDLE mutexHandle)
{
    if(!mutexHandle)
        return OPRT_OS_ADAPTER_INVALID_PARM;

    P_MUTEX_MANAGE pMutexManage;
    pMutexManage = (P_MUTEX_MANAGE)mutexHandle;
    
    BaseType_t ret;
    ret = xSemaphoreTake(pMutexManage->mutex, portMAX_DELAY);
    if(pdTRUE != ret) {
        return OPRT_OS_ADAPTER_MUTEX_LOCK_FAILED;
    }

    return OPRT_OS_ADAPTER_OK;
}

/**
 * @brief   用于unlock tuya mutex
 * 
 * @param[in] mutexHandle tuya mutex句柄
 * @return int 0=成功，非0=失败
 */
int bull_hal_sys_mutex_unlock(const MUTEX_HANDLE mutexHandle)
{
    if(!mutexHandle)
        return OPRT_OS_ADAPTER_INVALID_PARM;
    
    P_MUTEX_MANAGE pMutexManage;
    pMutexManage = (P_MUTEX_MANAGE)mutexHandle;
    
    BaseType_t ret;
    if(FALSE == bull_hal_sys_is_in_isr()) {
        ret = xSemaphoreGive(pMutexManage->mutex);
    }else {
        signed portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE;
        ret = xSemaphoreGiveFromISR(pMutexManage->mutex,\
                                    &xHigherPriorityTaskWoken);
        portYIELD_FROM_ISR_ex(xHigherPriorityTaskWoken);
    }
    if(pdTRUE != ret) {
        return OPRT_OS_ADAPTER_MUTEX_UNLOCK_FAILED;
    }


    return OPRT_OS_ADAPTER_OK;
}

/**
 * @brief  用于释放tuya mutex
 * 
 * @param[in] mutexHandle MUTEX_HANDLE tuya mutex句柄
 * @return int 0=成功，非0=失败
 */
int bull_hal_sys_mutex_delete(const MUTEX_HANDLE mutexHandle)
{
    if(!mutexHandle)
        return OPRT_OS_ADAPTER_INVALID_PARM;

    P_MUTEX_MANAGE pMutexManage;
    pMutexManage = (P_MUTEX_MANAGE)mutexHandle;
    
    vSemaphoreDelete(pMutexManage->mutex);

    bull_hal_sys_memory_free(mutexHandle);

    return OPRT_OS_ADAPTER_OK;
}
